#ifndef _WM_H_
#define _WM_H_

#include "common.h"

#ifdef _WM_EXPOSE_ALL

#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>

#ifndef WIN32
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <X11/extensions/xf86vmode.h>
#else
#include <windows.h>
#endif

#define SYM_TYPE_NONE	0x00
#define SYM_TYPE_MOUSE	0x01
#define SYM_TYPE_KEY	0x02
#define SYM_TYPE_SKEY	0x03
#define SYM_TYPE_MOD	0x04

#define EVENT_NONE		0x00
#define EVENT_BUTTON_DOWN	0x01
#define EVENT_BUTTON_UP		0x02
#define	EVENT_KEY_DOWN		0x03
#define EVENT_KEY_UP		0x04
#define EVENT_MOUSE_MOTION	0x05

#define MOUSE_BUTTON_LEFT	0x00
#define MOUSE_BUTTON_RIGHT	0x01
#define MOUSE_BUTTON_CENTRE	0x02
#define MOUSE_BUTTON_UP		0x03
#define MOUSE_BUTTON_DOWN	0x04
#define MOUSE_MOTION		0x05

#define SYM_MOD_CTRL	0x01
#define SYM_MOD_ALT	0x02
#define SYM_MOD_SHIFT	0x04
#define SYM_MOD_SUPER	0x08

#define SYM_KEY_SPACE	0x01
#define SYM_KEY_ESCAPE	0x02
#define SYM_KEY_TAB	0x03
#define SYM_KEY_KP0	0x04
#define SYM_KEY_KP1	0x05
#define SYM_KEY_KP2	0x06
#define SYM_KEY_KP3	0x07
#define SYM_KEY_KP4	0x08
#define SYM_KEY_KP5	0x09
#define SYM_KEY_KP6	0x0A
#define SYM_KEY_KP7	0x0B
#define SYM_KEY_KP8	0x0C
#define SYM_KEY_KP9	0x0D
#define SYM_KEY_UP	0x0E
#define SYM_KEY_DOWN	0x0F
#define SYM_KEY_LEFT	0x10
#define SYM_KEY_RIGHT	0x11
#define SYM_KEY_F1	0x12
#define SYM_KEY_F2	0x13
#define SYM_KEY_F3	0x14
#define SYM_KEY_F4	0x15
#define SYM_KEY_F5	0x16
#define SYM_KEY_F6	0x17
#define SYM_KEY_F7	0x18
#define SYM_KEY_F8	0x19
#define SYM_KEY_F9	0x1A
#define SYM_KEY_F10	0x1B
#define SYM_KEY_F11	0x1C
#define SYM_KEY_F12	0x1D
#define SYM_KEY_BCKSPC	0x1E
#define SYM_KEY_DELETE	0x1F
#define SYM_KEY_ENTER	0x20
#define SYM_KEY_RETURN	SYM_KEY_ENTER
#define SYM_KEY_KPEQ	0x21
#define SYM_KEY_KPMUL	0x22
#define SYM_KEY_KPADD	0x23
#define SYM_KEY_KPSUB	0x24
#define SYM_KEY_KPDOT	0x25
#define SYM_KEY_KPDIV	0x26

#ifndef _HAVE_CURSOR_TYPE
#define _HAVE_CURSOR_TYPE
struct material_s;
typedef struct cursor_s {
	struct material_s *mat;
	int w;
	int h;
	int x;
	int y;
} cursor_t;
#endif

#ifndef _HAVE_WM_TYPE
#define _HAVE_WM_TYPE
typedef struct wm_s {
	struct {
		int height;
		int width;
		int max_height;
		int max_width;
	} size;

	int fullscreen;
	int frame_cap;
	int lfps[4];
	int lfps_i;
	int fps;
	char* title;
	GLfloat distance;
	int isinit;
	cursor_t cursor;

#ifndef WIN32
	Display *dpy;
	int screen;
	Window win;
	GLXWindow glxwin;
	GLXContext ctx;
        GLXFBConfig fb_cfg;
	XSetWindowAttributes attr;
	int dblbuff;
	XF86VidModeModeInfo deskMode;
	XF86VidModeModeInfo **modes;
	XVisualInfo *vi;
	int mode;
	int mode_count;
	XIM im;
	XIC ic;
	XIMStyle style;
#else
	HDC hDC;
	HGLRC hRC;
	HWND hWnd;
	HINSTANCE hInstance;
#endif
} wm_t;
#endif

#ifndef _HAVE_CAMERA_TYPE
#define _HAVE_CAMERA_TYPE
typedef struct camera_s {
	float x;
	float y;
	float z;
	float yaw;
	float pitch;
} camera_t;
#endif

#ifndef _HAVE_SYM_TYPE
#define _HAVE_SYM_TYPE
typedef struct sym_s {
	uint8_t type;
	uint32_t sym;
	uint32_t ch;
} sym_t;
#endif

#ifndef _HAVE_BIND_TYPE
#define _HAVE_BIND_TYPE
typedef struct bind_s {
	char str[256];
	sym_t sym;
	uint8_t mods;
} bind_t;
#endif

#ifndef _HAVE_EVENT_TYPE
#define _HAVE_EVENT_TYPE
typedef struct event_s {
	uint8_t type;
	sym_t sym;
	int x;
	int y;
	int rx;
	int ry;
} event_t;
#endif

#ifndef _HAVE_ACTION_TYPE
#define _HAVE_ACTION_TYPE
typedef struct action_s {
	struct action_s *prev;
	struct action_s *next;
	char name[256];
	uint32_t h;
	bind_t bind;
	void (*func)(event_t *e);
	void (*r_func)(event_t *e);
	void (*a_func)(event_t *e);
	char* com;
} action_t;
#endif

/* defined in wm.c */
extern wm_t wm_data;

/* defined in wm.c */
void wm_capture(char* file);

/* defined in wm_x11.c and wm_w32.c */
int wm_init(void);
void wm_exit(void);
int wm_create(void);
int wm_resize(void);
int wm_update(void);
void wm_destroy(void);
void wm_toggle_fullscreen(int fs);
void wm_cursor(char* file, int width, int height, int offset_x, int offset_y);
void wm_grab(void);
void wm_ungrab(void);
void wm_title(char* title);

/* defined in camera.c */
void camera_view_matrix(matrix_t *mat, camera_t *cam);
camera_t *camera_get(void);
void camera_set_pos(v3_t *p);
void camera_set_yaw(GLfloat yaw);
void camera_set_pitch(GLfloat pitch);

/* defined in kmap.c */
int kmap_strtobind(bind_t *bind, char* str);
int kmap_bindtostr(char* str, int size, bind_t *bind);
int kmap_equal(bind_t *b1, bind_t *b2);
int kmap_triggers(bind_t *eb, bind_t *ab);

/* defined in events.c */
int events_init(void);
void events_exit(void);
void events_set_mousegrab(uint8_t g);
uint8_t events_get_mousegrab(void);
void events_get_mouse(int p[2]);
void events_set_mouse(int x, int y);
void event_remove(char* name);
void event_create(char* name, char* bind, char* com, void (*func)(event_t *e), void (*r_func)(event_t *e), void (*a_func)(event_t *e));
void events_trigger_active(void);
void events_handle(event_t *e);

/* defined in wm_x11.c and wm_w32.c */
void events_main(void);

#endif

/* defined in wm.c and dummy.c */
int wm_width_setter(char* value);
int wm_height_setter(char* value);
int wm_cap_setter(char* value);
int wm_fullscreen_setter(char* value);

/* defined in opengl.c and dummy.c */
int opengl_anisotropic_setter(char* value);
int opengl_bilinear_setter(char* value);
int opengl_trilinear_setter(char* value);
int opengl_mipmap_setter(char* value);
int opengl_particles_setter(char* value);
int opengl_particles_max_setter(char* value);
int opengl_bumpmap_setter(char* value);
int opengl_psdf_setter(char* value);
int opengl_shadowpass_setter(char* value);
int opengl_shadowsize_setter(char* value);

/* defined in events.c and dummy.c */
void events_save(file_t *f);
int event_bind(array_t *a);

/* defined in ui.c and dummy.c */
int ui_scale_setter(char* value);
int ui_autoscale_setter(char* value);

#endif
